import events from 'events';
import fetch from 'node-fetch';
import { llog, lerror } from './logger';
import { sleep } from './tools';
import { getOpenedOrders, closeOrder, cancelOrder } from '../models/Order';

const EVT_UPDATE_PRICE = Symbol('evt_update_price');

let randomSign = () => {
	return Math.random() > 0.5 ? 1 : -1;
};

export class TickData {
	realPrice: number;
	genPrice: number;
	genBase: number;
}

export class TickManager {
	ticks: TickData[];
	startTickTime: number;
	lastTickTime: number;
	currentTick: number;
	chargeInterval: number;
	nextKeyTick: number;
	tmGenerator: any;
	tmPuller: any;
	pullInterval: number;

	pricePuller: () => { price: number; time: number };

	constructor(data) {
		Object.assign(this, data);
	}

	start() {
		this.ticks = [];
		this.startTickTime = Date.now();
		this.lastTickTime = Date.now();
		this.currentTick = 0;
		this.chargeInterval = 5;
		this.pullInterval = 3 * 1000;
		this.nextKeyTick = this.currentTick + this.pullInterval;

		this.tmPuller = setInterval(async () => {
			try {
				let p = await this.pricePuller();
				console.log('pull price', this.currentTick, p);
				this.setNextRealPrice(p.price);
			} catch (e) {
				llog('pull price error', e);
			}
		}, this.pullInterval);

		this.tmGenerator = setInterval(() => {
			let p = this.pricePuller();
			this.updateCurrentTick();
		}, 1000);
	}

	stop() {
		if (this.tmPuller) {
			clearInterval(this.tmPuller);
			this.tmPuller = undefined;
		}
		if (this.tmGenerator) {
			clearInterval(this.tmGenerator);
			this.tmGenerator = undefined;
		}
	}

	getCurrentPrice() {
		if (!this.currentTick) return -1;
		let curTick = this.ticks[this.currentTick];
		// if (!curTick) return -1;
		return curTick.genPrice;
	}

	setNextRealPrice(price: number) {
		//
		let next = 3;
		let nt = this.ticks[this.currentTick + next];
		if (!nt) {
			nt = new TickData();
			this.ticks[this.currentTick + next] = nt;
		}
		nt.realPrice = price;
		llog('setprice', this.currentTick, '->' + (this.currentTick + next), price);
	}

	async updateCurrentTick() {
		let now = Date.now();
		let nowSec = Math.floor(now / 1000);
		let lastSec = Math.floor(this.lastTickTime / 1000);
		let ds = nowSec - lastSec;
		this.currentTick += ds;
		this.lastTickTime = now;
		llog('---> begin tick', this.currentTick, '+' + ds, 'time', nowSec);

		// 生成本帧价格
		this.resolveCurPrice();

		// 处理新提交的新订单
		await this.processOrders(nowSec - 1);
	}

	async processOrders(sec) {
		// let orders = await getOrderByTime(sec, true);
		let orders = await getOpenedOrders();
		llog('check new', sec, orders.length);
		if (!orders.length) return;

		let now = Date.now();
		let lastTick = this.ticks[this.currentTick - 1];
		if (!lastTick) {
			// 上一秒的价格，如果上一秒价格还未生成，是不能接受订单的
		} else {
			let expiredOrders = [];
			let validOrders = [];
			orders.forEach(p => {
				if (now - p.createdTime > 2 * 1000) {
					// expiredOrders.push(p);
					cancelOrder(p);
				} else {
					validOrders.push(p);
				}
			});

			// 根据订单情况和当时报价，计算结算帧的评估价
			let changeDirection;
			let totalForUp = 0,
				totalForDown = 0;
			validOrders.forEach(p => {
				// console.log(p);
				if (p.target == 'up') totalForUp += p.amount;
				else if (p.target == 'down') totalForDown += p.amount;
			});
			if (totalForUp >= totalForDown) {
				changeDirection = 1;
			} else {
				changeDirection = -1;
			}
			let targetTick = new TickData();
			let ti = this.currentTick + this.chargeInterval;
			this.ticks[ti] = targetTick;
			targetTick.genBase = lastTick.genPrice * changeDirection;
			llog('gen base for tick', ti);

			validOrders.forEach(p => {
				closeOrder(p.id, targetTick.genBase);
			});
		}
	}

	resolveCurPrice() {
		let curTick = this.ticks[this.currentTick];
		if (curTick) {
			// 如果当前帧已经有评估值，需要合成一个有效价格
			if (curTick.genBase) {
				let av = Math.abs(curTick.genBase);
				let si = curTick.genBase > 0 ? 1 : -1;
				let rk = Math.random() * 2 + 1;
				curTick.genPrice = av * (1 + si * 0.001 * rk);
				llog('genprice1', curTick.genPrice);
			} else {
				// 没有评估值，那么就是有真实报价
				let np = this.nextRealPrice();
				llog('genprice2');
				// 如果自己是关键帧
				if (curTick.realPrice) {
					curTick.genPrice = curTick.realPrice;
				} else {
					// 先找到下一刻的真实报价
					// 如果有评估价
					if (curTick.genBase) {
						curTick.genPrice = curTick.genBase + (np - Math.abs(curTick.genBase)) * 0.05;
					} else {
						curTick.genPrice = np;
					}
				}
			}
		} else {
			// 空帧，生成一个随机价格
			let np = this.nextRealPrice();
			let rk = Math.random() * 5 + 1;
			curTick = new TickData();
			curTick.genPrice = np * (1 + randomSign() * (0.001 * rk));
			this.ticks[this.currentTick] = curTick;
			llog('genprice3', curTick.genPrice);
		}
	}

	nextRealPrice() {
		for (let i = 0; i <= 5; i++) {
			let nt = this.ticks[this.currentTick + i];
			if (nt && nt.realPrice) {
				llog('find realprice', '<-', this.currentTick + i, nt.realPrice);
				return nt.realPrice;
			}
		}
	}
}
